package home

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"time"
)

type un uint64

func (u un) toString() string {
	return fmt.Sprintf("%09o", u)
}

var hexs = [6]un{0, 1, 3, 4, 5, 7}
var dexs = [8]int{0, 1, 65535, 2, 3, 4, 65535, 5}

const byte_wid = 3 // 一个字字长 2^3
const byte_kid = 6 // len(hex) = 6
const byte_len = 9 // 数字串长，也是循环数
const byte_move = un(byte_wid * (byte_len - 1))
const byte_max = un((1 << (byte_len * byte_wid)) + 1)
const mask_0 = un(0o_111_111_111) //0b_001_001_001_001_001_001_001_001_001
const mask_1 = un(mask_0 << 1)
const mask_2 = un(mask_1 << 1)

// const mask_h = ^mask_e
// const mask_e = 0o7 //0b111
const mask_e = un(0o7 << byte_move)
const mask_u = un(0o7)

func next_9(h un) un {
	// fmt.Printf("\n h   %03o", h)

	b2 := (h & mask_2) >> 2
	// fmt.Printf("\n b2  %03o", b2)

	h = (h & mask_e >> byte_move) | ((h & ^mask_e) << byte_wid)
	// fmt.Printf("\n ha  %03o", h)

	b1 := (h & mask_1) >> 1
	// fmt.Printf("\n b1  %03o", b1)

	b0 := h & mask_0
	// fmt.Printf("\n b0  %03o", b0)

	// fmt.Printf("\n r2  %03o", ((b2 ^ b1 ^ b0) << 2))
	// fmt.Printf("\n r1  %03o", ((b2 & b0) << 1))
	// fmt.Printf("\n r0  %03o", (b2 | b1))
	// fmt.Printf("\n rtn %03o", ((b2^b1^b0)<<2)|((b2&b0)<<1)|(b2|b1))
	// fmt.Printf("\n-------\n")

	return ((b2 ^ b1 ^ b0) << 2) | ((b2 & b0) << 1) | (b2 | b1)
}

func un2int(u un) int {
	i := 0
	for c := 1; u > 0; u, c = u>>byte_wid, c*6 {
		i += dexs[int(u&mask_u)] * c
	}
	return i
}

// func int2un(i int) un { }

var round_size = int(math.Pow(byte_kid, byte_len))

// type empty struct{}

var circle_0 = struct {
	hit   []un
	index []un
}{
	hit:   make([]un, round_size),
	index: []un{},
}

func do_circle(h un) {
	min := byte_max
	hashs := [byte_len]un{}
	for i := 0; i < byte_len; i++ {
		h = (h & mask_e >> byte_move) | ((h & ^mask_e) << byte_wid)
		hashs[i] = h
		if min > h {
			min = h
		}
	}
	circle_0.index = append(circle_0.index, min)
	for _, v := range hashs {
		circle_0.hit[un2int(v)] = min
	}
}

var loop_0 = struct {
	hit   Bitmap
	index map[un](int)
}{
	hit:   Bitmap{},
	index: make(map[un](int)),
}

func do_loop(h un, writer *bufio.Writer) {
	p := un(0)
	min := byte_max
	u, size := un2int(h), 0
	for !loop_0.hit.Test(u) && size < round_size {
		p = circle_0.hit[u]
		h = next_9(p)
		if min > h {
			min = h
		}
		u = un2int(h)
		loop_0.hit.Set(un2int(p))
		size++
	}
	if size >= round_size {
		fmt.Printf("==================== size >= round_size, %d \n =================", size)
		fmt.Printf("==================== final h:, %09o \n =================", h)
		writer.WriteString(h.toString())
		writer.WriteString(",")
		if writer.Buffered() >= threshold {
			writer.Flush()
		}
	}
	loop_0.index[min] = size
}

const debug_line = 10

var threshold = 0

func Do_steps() {
	/* ===================================================
	   ======             init file               ========
	   =================================================== */

	// file, err := os.Create("./tmp/loop9.txt") // When Debug
	file, err := os.Create("./tmp/loop9.txt") // Path for main
	if err != nil {
		fmt.Println("Fail to Create file /tmp/loop9.txt:", err)
		return
	}
	defer file.Close()

	writer := bufio.NewWriter(file)
	bufferSize := writer.Available()

	// 定义缓冲区满的阈值
	threshold = bufferSize / 2

	// 创建一个每10秒触发一次的Ticker，用于定期检查缓冲区大小
	ticker := time.NewTicker(10 * time.Second)
	defer ticker.Stop() // 程序结束时停止Ticker

	go func() {
		for range ticker.C {
			if writer.Buffered() >= threshold {
				writer.Flush()
				fmt.Println("Flush buffer in Do_steps()")
			}
		}
	}()

	/* ===================================================
	   ======             do_circle               ========
	   =================================================== */
	ForW(byte_len, 0, 5)(func(idxs ...interface{}) {
		hex := un(0)
		for i := byte_len - 1; i >= 0; i-- {
			hex |= (hexs[idxs[i].(int)] << (i * byte_wid))
		}
		if circle_0.hit[un2int(hex)] == 0 {
			do_circle(hex)
		}
	})

	fmt.Println("============ circle_0 ================")
	dbg_cnt_c0 := 0
	fmt.Printf("circle_0.index size:%d, [\n\t\t", len(circle_0.index))
	for _, u := range circle_0.index {
		if dbg_cnt_c0 > debug_line {
			break
		}

		/*
			strs := make([]string, debug_line)
			for i, v := range hashs {
				strs[i] = v.toString()
			}
			fmt.Println("--", idx.toString(), ":", strs)
		*/
		fmt.Print(u.toString(), ",")
		dbg_cnt_c0++
	}
	fmt.Println("...\n]")
	// fmt.Println("=====hit=====", circle_0.hit, "====hit====")

	/* ===================================================
	   ======             do_loop                 ========
	   =================================================== */

	loop_0.hit.Init(round_size)
	for _, u := range circle_0.index {
		if !loop_0.hit.Test(un2int(u)) {
			do_loop(u, writer)
		}
	}

	fmt.Println("============ loop_0 ================")
	dbg_cnt_c1 := 0
	fmt.Println("loop_0.index size:", len(loop_0.index))
	for idx, hashs := range loop_0.index {
		if dbg_cnt_c1 > debug_line {
			break
		}

		/*
			strs := make([]string, debug_line)
			dbg_cnt_c10 := 0
			for _, i := range hashs {
				if dbg_cnt_c10 >= debug_line {
					break
				}
				strs[dbg_cnt_c10] = i.toString()
				dbg_cnt_c10++
			}
			fmt.Println("--", idx.toString(), ":", strs)
		*/
		fmt.Println("--", idx.toString(), "--size:", hashs)
		dbg_cnt_c1++
	}

	/* ===================================================
	   ======            get_clustor              ========
	   =================================================== */

	/*
		clustor_0 := make(map[un][]un)
		for clust, loop := range loop_0.index {
			clustor_0[clust] = make([]un, 0, byte_max)
			for idx := range loop {
				clustor_0[clust] = append(clustor_0[clust], circle_0.index[idx]...)
			}
		}
	*/

	clustor_0 := make(map[un]int)
	for clust, size := range loop_0.index {
		clustor_0[clust] = size * byte_len
	}

	fmt.Println("============ clustor_0 ================")
	fmt.Println("clustor_0.index size:", len(clustor_0))
	dbg_cnt_c2 := 0
	for idx, size := range clustor_0 {
		/*
			strs := make([]string, debug_line)
			dbg_cnt_c2 := 0
			for _, h := range hashs {
				if dbg_cnt_c2 >= debug_line {
					break
				}
				strs[dbg_cnt_c2] = h.toString()
				dbg_cnt_c2++
			}
			fmt.Println("--", idx.toString(), ":", strs, "size:", len(hashs))
		*/
		if dbg_cnt_c2 >= 3*debug_line {
			break
		}
		fmt.Println("--", idx.toString(), "--size:", size)
		dbg_cnt_c2++
	}

}
